Load libraries

library(tidytext)
library(tidyverse)
library(quanteda)
library(lubridate)
library(ggplot2)
library(plotly)
library(forcats)
library(readxl)
library(leaflet)
library(leaflet.minicharts)
library(sp)
library(sf)
library(readr)
library(stringr)
library(rtweet)
library(ggraph)
library(ggrepel)
library(tidygraph)

Load Data

Parlamentarier <- read_csv("Data/Parlamentarier.csv")

-- Column specification ------------------------------------------------------------------------------------------------------------------------------
cols(
  .default = col_character(),
  tags = col_logical(),
  Homepage_URL = col_logical(),
  SM_Twitter_id = col_double(),
  SM_Twitter_verifiziert = col_logical(),
  SM_Facebook_id = col_double(),
  SM_Facebook_verifiziert = col_logical(),
  SM_Youtube_user = col_logical(),
  SM_Youtube_id = col_logical(),
  SM_Youtube_verifiziert = col_logical(),
  SM_Instagram_user = col_logical(),
  SM_Instagram_id = col_logical(),
  SM_Instagram_verifiziert = col_logical(),
  SM_Telegram_user = col_logical(),
  SM_Telegram_id = col_logical(),
  SM_Telegram_verifiziert = col_logical(),
  created_at = col_datetime(format = ""),
  modified_at = col_datetime(format = "")
)
i Use `spec()` for the full column specifications.

EU-Parlament rausfiltern

Parlamentarier <- Parlamentarier %>% 
  filter(Kategorie!="EU-Parlament")

Read Tabellen mit fehlenden Geschlechtern

alle_geschlechter <- read_excel("Data/Parlamentarier_geschechter.xlsx", sheet = "Geschlechter")

Join fehlende Geschlechterangaben

Parlamentarier <- Parlamentarier %>% 
  left_join(alle_geschlechter, by = c("Name" = "Name"))

Rename Spalten

Parlamentarier <- Parlamentarier %>% 
  rename(Geschlecht = Geschlecht.y)

Bundestag Geschlechterverteilung pro Partei

bundestag <- Parlamentarier %>% 
  select(id, Name, Geschlecht, Partei, Kategorie, SM_Twitter_id, SM_Twitter_user) %>% 
  filter(Kategorie=="Bundestag")

bundestag$Partei[bundestag$Partei == "CSU"] <-"CDU/CSU"
bundestag$Partei[bundestag$Partei=="CDU"]<-"CDU/CSU"

bundestag_man <- bundestag %>% 
  group_by(Partei) %>% 
  filter(Geschlecht == "männlich") %>% 
  summarise(gesamt_man=n())

bundestag_gesamt <- bundestag %>% 
  group_by(Partei) %>% 
  filter(Geschlecht == "weiblich") %>% 
  summarise(gesamt_frau=n()) %>% 
  left_join(bundestag_man) %>% 
  mutate(row_sum=rowSums(.[2:3])) %>% 
  arrange(desc(row_sum))
Joining, by = "Partei"

Barchart Bundestag

  • Stacked-Barchart zur Geschlechterverteilung im Bundestag pro Partei
  • visualisierung der Daten in möglichst geschlechterneuralen Farben
plot_ly(data=bundestag_gesamt, x=~reorder(Partei,-row_sum), y=~gesamt_frau, name="weiblich", marker=list(color=toRGB("#FB7F62")),
        type="bar", hoverinfo="text", text=~paste("",row_sum), 
        hovertemplate=paste("Anzahl: %{y:,.0f}", 
                            "<br>Gesamtanzahl: %{text}")) %>% 
  add_trace(y=~gesamt_man, name="männlich", marker=list(color=toRGB("#775285"))) %>% 
  layout(barmode="stack", title="Geschlechterverteilung in den Parteien im Bundestag", # titel position und größe ändern
         xaxis = list(title = ""), yaxis=list(title="Anzahl Abgeordnete")) %>%
  layout(legend=list(x=1, y=0.5))

Landtag Geschlechterverteilung pro Partei

landtag_partei <- Parlamentarier %>% 
  filter(Kategorie !="Bundestag") %>% 
  filter(Kategorie!="EU-Parlament") %>% 
  filter(Partei !="BIW") %>% 
  filter(Partei!="SSW") %>% 
  filter(Partei!="BVB/FW") %>% 
  filter(Partei!="FW")
landtag_partei$Partei[landtag_partei$Partei == "CSU"] <-"CDU/CSU"
landtag_partei$Partei[landtag_partei$Partei=="CDU"] <- "CDU/CSU"
landtag_partei$Partei[landtag_partei$Partei=="FDP/DVP"] <- "FDP" 
landtag_man <- landtag_partei %>% 
  group_by(Partei) %>% 
  filter(Geschlecht=="männlich") %>% 
  summarise(gesamt_man=n())

landtag_gesamt <- landtag_partei %>% 
  group_by(Partei) %>% 
  filter(Geschlecht=="weiblich") %>% 
  summarise(gesamt_frau=n()) %>% 
  left_join(landtag_man) %>% 
   mutate(row_sum=rowSums(.[2:3])) %>% 
  arrange(desc(row_sum))
Joining, by = "Partei"

Barchart Landtag

  • Stacked-Barchart zur Geschlechterverteilung in den Landtagen pro Partei
  • visualisierung der Daten in möglichst geschlechterneuralen Farben
plot_ly(data=landtag_gesamt, x=~reorder(Partei,-row_sum), y=~gesamt_frau, name="weiblich", marker=list(color=toRGB("#FB7F62")), 
        type="bar", hoverinfo="text", text=~paste("",row_sum), 
        hovertemplate=paste("Anzahl: %{y:,.0f}", 
                            "<br>Gesamtanzahl: %{text}")) %>% 
  add_trace(y=~gesamt_man, name="männlich", marker=list(color=toRGB("#775285"))) %>% 
  layout(barmode="stack", title="Geschlechterverteilung in den Parteien in den Landtagen", # titel position und größe ändern
         xaxis=list(title=""), yaxis=list(title="Anzahl Abgeordnete")) %>%
  layout(legend=list(x=1, y=0.5))

Map mit Geschlechterverteilung in den Landtagen

parlamentarier_landtag <- Parlamentarier %>% 
  filter(Kategorie %in% c("Abgeordnetenhaus von Berlin", 
                          "Bayerischer Landtag", 
                          "Bremische Bürgerschaft", 
                          "Hamburgische Bürgerschaft", 
                          "Hessischer Landtag", 
                          "Landtag Brandenburg", 
                          "Landtag des Saarlandes", 
                          "Landtag Mecklenburg-Vorpommern", 
                          "Landtag Nordrhein-Westfalen", 
                          "Landtag Rheinland-Pfalz", 
                          "Landtag Sachsen-Anhalt", 
                          "Landtag von Baden-Württemberg", 
                          "Niedersächsischer Landtag", 
                          "Sächsischer Landtag", 
                          "Schleswig-Holsteinischer Landtag", 
                          "Thüringer Landtag"))
Kategorie <- c("Abgeordnetenhaus von Berlin", 
               "Bayerischer Landtag", 
               "Bremische Bürgerschaft",
               "Hamburgische Bürgerschaft", 
               "Hessischer Landtag",
               "Landtag Brandenburg", 
               "Landtag des Saarlandes",
               "Landtag Mecklenburg-Vorpommern",
               "Landtag Nordrhein-Westfalen",
               "Landtag Rheinland-Pfalz",
               "Landtag Sachsen-Anhalt", 
               "Landtag von Baden-Württemberg", 
               "Niedersächsischer Landtag", 
               "Sächsischer Landtag", 
               "Schleswig-Holsteinischer Landtag", 
               "Thüringer Landtag")

lat <- c(52.520008,
         48.917431,
         53.074982,
         53.553815,
         50.652052,
         52.408418,
         49.396423,
         53.612651,
         51.433237,
         50.118346,
         51.950265,
         48.661604,
         52.636704,
         51.104541,
         54.219367,
         51.010989)

lng <- c(13.404954,
         11.407980,
         8.807080,
         9.991575,
         9.162438,
         12.562492,
         7.022961,
         12.429595,
         7.661594,
         7.308953,
         11.692274,
         9.350134,
         9.845077,
         13.201738,
         9.696117,
         10.845346)

bundeslaender_koordinaten <- data.frame(Kategorie, lat, lng)
parlamentarier_man <- parlamentarier_landtag %>% 
  group_by(Kategorie) %>% 
  filter(Geschlecht == "männlich") %>% 
  summarise(männlich = n())

parlamentarier_landtag_gesamt <- parlamentarier_landtag %>% 
  group_by(Kategorie) %>% 
  filter(Geschlecht == "weiblich") %>% 
  summarise(weiblich = n()) %>% 
  left_join(parlamentarier_man)
Joining, by = "Kategorie"
parlamentarier_koordinaten <- parlamentarier_landtag_gesamt %>% 
  left_join(bundeslaender_koordinaten, by = c("Kategorie" = "Kategorie"))

Map mit Pie-Charts

colors <- c("#FB7F62", "#775285")

grenzen <- readRDS("Data/gadm36_DEU_1_sp.rds") %>% 
  st_as_sf()

popup_bundeslaender <- paste0("<strong>Bundesland: </strong>", grenzen$NAME_1)
map <- leaflet() %>% 
  addProviderTiles(providers$CartoDB.VoyagerLabelsUnder) %>% 
  setView(lng = 10.451526, lat = 51.165691, zoom = 5.5) %>% 
  addPolygons(data = grenzen,
              fillColor = "grey",
              fillOpacity = 0.1,
              weight = 3,
              color = "grey",
              popup = popup_bundeslaender) %>% 
  addMinicharts(
    parlamentarier_koordinaten$lng, parlamentarier_koordinaten$lat,
    type = "pie",
    chartdata = parlamentarier_koordinaten[, c("weiblich", "männlich")],
    colorPalette = colors,
    width = 46,
    height = 46,
    opacity = 0.8,
    legendPosition = "bottomright"
  )
sf layer has inconsistent datum (+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs).
Need '+proj=longlat +datum=WGS84'
map

Tweets der Politiker*innen scrapen

Nicht als ausführbaren Code, damit die Daten nicht nochmals gezogen werden…

Twitter_accounts <- Parlamentarier %>% filter(Kategorie!=“EU-Parlament”) %>% filter(Partei!=“BIW”) %>% filter(Partei!=“SSW”) %>% filter(Partei!=“BVB/FW”) %>% filter(Partei!=“FW”) %>% filter(Partei!=“fraktionslos”) %>% filter(SM_Twitter_user != "")

token <- get_token() token

alle_tweets <- list() userIdList = list(Twitter_accounts\(SM_Twitter_user) rl <- rate_limit(token, "statuses/user_timeline") for(user in userIdList[[1]]){ alle_tweets[[user]] <- get_timeline(user, n = 2, check = F) print("rate limit remaining:", str(rl\)remaining)) print(“at user:”, str(user)) rl <- rl %>% mutate(remaining = remaining - 1) # if rate limit exhausted, then wait to rate limit reset if (rl\(remaining == 5L) { rl <- rate_limit(token, "statuses/user_timeline") print("rate limit exceeded, waiting for 900s at user", str(user)) Sys.sleep(as.numeric(rl\)reset, “secs”)) } }

Nach relevanten Hashtags filtern

  • “alle_tweets.rds” ist die Datei mit allen gezogenen Tweets.
  • nach relevanten Tweets filtern mit vorher bestimmten Hashtags (“Twitter-Hashtags.xlsx”), Tweets in Kleinschreibung formatieren und als “final_tweets.rds” exportieren.
alle_tweets <- read_rds("Data/alle_tweets.rds")

suchbegriffe <- read_excel("Data/Twitter-Hashtags.xlsx", sheet ="Tabelle2")

suchbegriffe_vector <- suchbegriffe$Hashtags

alle_tweets <- bind_rows(alle_tweets)

alle_tweets <- alle_tweets %>% 
  mutate(text = tolower(text))

filtert_tweets <- alle_tweets %>% 
  filter(str_detect(text, paste (suchbegriffe_vector, collapse = "|")))

write_rds(filtert_tweets, "final_tweets.rds")

Sentimentanalyse

Parlamentarier_senti <- Parlamentarier %>% 
  filter(Partei!="BIW") %>% 
  filter(Partei!="SSW") %>% 
  filter(Partei!="BVB/FW") %>% 
  filter(Partei!="FW") %>% 
  filter(Partei!="fraktionslos") %>% 
  filter(SM_Twitter_user != "") %>% 
  select(Name, Partei, SM_Twitter_user, Geschlecht) %>% 
  mutate(SM_Twitter_user=tolower(SM_Twitter_user))
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "CSU"] <- "CDU/CSU"
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "CDU"] <- "CDU/CSU"
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "FDP/DVP"] <- "FDP" 
load("Data/sentiWS.RData")
sentiws <- dictionary(list(positive=positive, negative=negative))
tweet_corpus <- corpus(filtert_tweets, text_field = "text")
token <- tokens(tweet_corpus)
dfm <- dfm(token)

senti <- dfm_lookup(dfm, sentiws)  
senti <- dfm_group(senti, groups = screen_name)
senti_frame <- senti %>% 
  convert(to= "data.frame") %>% 
  as_tibble() %>% 
  mutate(doc_id=tolower(doc_id))
Fehler in UseMethod("convert") : 
  nicht anwendbare Methode für 'convert' auf Objekt der Klasse "c('dfm', 'dgCMatrix', 'CsparseMatrix', 'dsparseMatrix', 'generalMatrix', 'dCsparseMatrix', 'dMatrix', 'sparseMatrix', 'compMatrix', 'Matrix', 'xMatrix', 'mMatrix', 'Mnumeric', 'replValueSp')" angewendet

Barchart

  • Partei absteigend nach negativem Sentiment sortieren
  • Beschriftung der X- und Y Werte ändern
  • Barchart bilden und in ggplotly konvertieren
senti_bar <- senti_final_frame %>% 
  mutate(Partei = fct_reorder(Partei, positive, max)) %>% 
  pivot_longer(c(positive, negative), values_to = c("Verhältnis"), names_to = c("Äußerung")) %>% 
  ggplot() + 
  geom_bar(aes(Partei,
               Verhältnis,               
               fill = Äußerung),
           position = "stack",
           stat = "identity") +
  scale_fill_manual(values = c("#f46666", "#8EC9BB")) + 
  theme_classic() + 
  labs(
    title = "Äußerungen der Politiker*innen auf Twitter zum Thema 'Gender'",
    subtitle = "Einschätzung durch Sentimentanalyse",
    x = "Partei",
    y = "Verhältnis",
    fill = "Äußerung"
  )

final_senti_plot <- ggplotly(senti_bar)
final_senti_plot

Twitter Netzwerk

tweets_network <- filtert_tweets %>% 
  select(screen_name,
         retweet_screen_name,
         created_at) %>% 
  mutate(screen_name = tolower(screen_name))
parlamentarier_network <- Parlamentarier %>% 
  select(Name,
         Partei,
         SM_Twitter_user) %>% 
  drop_na(SM_Twitter_user) %>% 
  mutate(SM_Twitter_user = tolower(SM_Twitter_user)) %>% 
  rename("screen_name" = "SM_Twitter_user")

network_data <- parlamentarier_network %>% 
  left_join(tweets_network, by = "screen_name")
hauefigkeit_tweets <- network_data %>% 
  count(screen_name)

network_data <- network_data %>% 
  left_join(hauefigkeit_tweets, by = "screen_name")
screen_suche <- parlamentarier_network$screen_name

filtered_retweeters <- network_data %>% 
  filter(str_detect(retweet_screen_name, paste (screen_suche, collapse = "|")))
netz <- filtered_retweeters %>% 
  filter(!is.na(retweet_screen_name)) %>% 
  select(from = screen_name, to = retweet_screen_name) %>% 
  as_tbl_graph

netz <- netz %>% 
  mutate(
    degree = centrality_degree(mode = "in"), 
    component = group_components()
  ) %>% 
  left_join(network_data %>% 
              select(Name, screen_name, Partei, n) %>% distinct(screen_name, .keep_all = T),
            by = c( "name" ="screen_name")) 
partei_farben <- list(
  "CDU/CSU" = "black",
  "SPD" = "red",
  "CSU" = "black",
  "FDP" = "#e2b007",
  "GRÜNE" = "#07C23F",
  "LINKE" = "#de4c8a", 
  "AfD" = "blue"
)

Netzwerk

Zuweisung von Attributen an Nodes: * Parteizugehörigkeit in Farbe * Klarname der Politikerinnen als Label Anzahl der Tweets in Größe

netz_plot <- netz %>% 
  filter(component <= 6) %>% 
  mutate(degree = centrality_degree(mode = "in")) %>% 
  ggraph(layout = "fr") +
  geom_edge_link(alpha = 0.25, arrow = arrow(length = unit("5", "mm"))) +
  geom_node_point(aes(size = n, color = Partei)) + 
  scale_color_manual(values = partei_farben) +
  theme_graph(background = "white") + # theme
  geom_node_label(aes(filter = n >= 15, label = Name), repel = T, show.legend = F, alpha = 0.5) + #position = "jitter"
  labs(title = "Retweet-Netzwerke deutscher Politiker*innen", size = "Anzahl Tweets", subtitle = "zum Thema 'Gender' ab 2016")
netz_plot 

NODES DEUTLICHERE ABSTUFUNG, VLT. THEME FUNKTIONIERT NICHT RICHTIG

LS0tDQp0aXRsZTogIlJfUHJvamVrdF9HZW5kZXIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyBMb2FkIGxpYnJhcmllcyANCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl0ZXh0KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHF1YW50ZWRhKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZm9yY2F0cykNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShsZWFmbGV0Lm1pbmljaGFydHMpDQpsaWJyYXJ5KHNwKQ0KbGlicmFyeShzZikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KHJ0d2VldCkNCmxpYnJhcnkoZ2dyYXBoKQ0KbGlicmFyeShnZ3JlcGVsKQ0KbGlicmFyeSh0aWR5Z3JhcGgpDQpgYGANCg0KIyBMb2FkIERhdGEgDQoNCmBgYHtyfQ0KUGFybGFtZW50YXJpZXIgPC0gcmVhZF9jc3YoIkRhdGEvUGFybGFtZW50YXJpZXIuY3N2IikNCmBgYA0KDQpFVS1QYXJsYW1lbnQgcmF1c2ZpbHRlcm4NCmBgYHtyfQ0KUGFybGFtZW50YXJpZXIgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBmaWx0ZXIoS2F0ZWdvcmllIT0iRVUtUGFybGFtZW50IikNCmBgYA0KDQpSZWFkIFRhYmVsbGVuIG1pdCBmZWhsZW5kZW4gR2VzY2hsZWNodGVybg0KYGBge3J9DQphbGxlX2dlc2NobGVjaHRlciA8LSByZWFkX2V4Y2VsKCJEYXRhL1BhcmxhbWVudGFyaWVyX2dlc2NoZWNodGVyLnhsc3giLCBzaGVldCA9ICJHZXNjaGxlY2h0ZXIiKQ0KYGBgDQoNCkpvaW4gZmVobGVuZGUgR2VzY2hsZWNodGVyYW5nYWJlbiANCmBgYHtyfQ0KUGFybGFtZW50YXJpZXIgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBsZWZ0X2pvaW4oYWxsZV9nZXNjaGxlY2h0ZXIsIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKQ0KYGBgDQoNClJlbmFtZSBTcGFsdGVuDQpgYGB7cn0NClBhcmxhbWVudGFyaWVyIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgcmVuYW1lKEdlc2NobGVjaHQgPSBHZXNjaGxlY2h0LnkpDQpgYGANCg0KIyBCdW5kZXN0YWcgR2VzY2hsZWNodGVydmVydGVpbHVuZyBwcm8gUGFydGVpDQoNCiogZmlsdGVybiBuYWNoIEJ1bmRlc3RhZw0KKiBDRFUgJiBDU1UgenVzYW1tZW5mw7xnZW4gDQoqIG5hY2ggbcOkbm5saWNoIHVuZCB3ZWlibGljaCBncnVwcGllcmVuLCBBbnphaGwgYmVyZWNobmVuIHVuZCBzb3J0aWVyZW4NCmBgYHtyfQ0KYnVuZGVzdGFnIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgc2VsZWN0KGlkLCBOYW1lLCBHZXNjaGxlY2h0LCBQYXJ0ZWksIEthdGVnb3JpZSwgU01fVHdpdHRlcl9pZCwgU01fVHdpdHRlcl91c2VyKSAlPiUgDQogIGZpbHRlcihLYXRlZ29yaWU9PSJCdW5kZXN0YWciKQ0KDQpidW5kZXN0YWckUGFydGVpW2J1bmRlc3RhZyRQYXJ0ZWkgPT0gIkNTVSJdIDwtIkNEVS9DU1UiDQpidW5kZXN0YWckUGFydGVpW2J1bmRlc3RhZyRQYXJ0ZWk9PSJDRFUiXTwtIkNEVS9DU1UiDQoNCmJ1bmRlc3RhZ19tYW4gPC0gYnVuZGVzdGFnICU+JSANCiAgZ3JvdXBfYnkoUGFydGVpKSAlPiUgDQogIGZpbHRlcihHZXNjaGxlY2h0ID09ICJtw6RubmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZShnZXNhbXRfbWFuPW4oKSkNCg0KYnVuZGVzdGFnX2dlc2FtdCA8LSBidW5kZXN0YWcgJT4lIA0KICBncm91cF9ieShQYXJ0ZWkpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQgPT0gIndlaWJsaWNoIikgJT4lIA0KICBzdW1tYXJpc2UoZ2VzYW10X2ZyYXU9bigpKSAlPiUgDQogIGxlZnRfam9pbihidW5kZXN0YWdfbWFuKSAlPiUgDQogIG11dGF0ZShyb3dfc3VtPXJvd1N1bXMoLlsyOjNdKSkgJT4lIA0KICBhcnJhbmdlKGRlc2Mocm93X3N1bSkpDQpgYGANCg0KIyMjIEJhcmNoYXJ0IEJ1bmRlc3RhZw0KDQoqIFN0YWNrZWQtQmFyY2hhcnQgenVyIEdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW0gQnVuZGVzdGFnIHBybyBQYXJ0ZWkNCiogdmlzdWFsaXNpZXJ1bmcgZGVyIERhdGVuIGluIG3DtmdsaWNoc3QgZ2VzY2hsZWNodGVybmV1cmFsZW4gRmFyYmVuDQpgYGB7cn0NCnBsb3RfbHkoZGF0YT1idW5kZXN0YWdfZ2VzYW10LCB4PX5yZW9yZGVyKFBhcnRlaSwtcm93X3N1bSksIHk9fmdlc2FtdF9mcmF1LCBuYW1lPSJ3ZWlibGljaCIsIG1hcmtlcj1saXN0KGNvbG9yPXRvUkdCKCIjRkI3RjYyIikpLA0KICAgICAgICB0eXBlPSJiYXIiLCBob3ZlcmluZm89InRleHQiLCB0ZXh0PX5wYXN0ZSgiIixyb3dfc3VtKSwgDQogICAgICAgIGhvdmVydGVtcGxhdGU9cGFzdGUoIkFuemFobDogJXt5OiwuMGZ9IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5HZXNhbXRhbnphaGw6ICV7dGV4dH0iKSkgJT4lIA0KICBhZGRfdHJhY2UoeT1+Z2VzYW10X21hbiwgbmFtZT0ibcOkbm5saWNoIiwgbWFya2VyPWxpc3QoY29sb3I9dG9SR0IoIiM3NzUyODUiKSkpICU+JSANCiAgbGF5b3V0KGJhcm1vZGU9InN0YWNrIiwgdGl0bGU9Ikdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW4gZGVuIFBhcnRlaWVuIGltIEJ1bmRlc3RhZyIsICMgdGl0ZWwgcG9zaXRpb24gdW5kIGdyw7bDn2Ugw6RuZGVybg0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIiIpLCB5YXhpcz1saXN0KHRpdGxlPSJBbnphaGwgQWJnZW9yZG5ldGUiKSkgJT4lDQogIGxheW91dChsZWdlbmQ9bGlzdCh4PTEsIHk9MC41KSkNCmBgYA0KDQojIExhbmR0YWcgR2VzY2hsZWNodGVydmVydGVpbHVuZyBwcm8gUGFydGVpDQoNCiogZmlsdGVybiBhbGxlbiBMYW5kdGFnZW4NCiogQ0RVICYgQ1NVIHNvd2llIEZEUCAmIERWUCB6dXNhbW1lbmbDvGdlbiANCiogbmFjaCBtw6RubmxpY2ggdW5kIHdlaWJsaWNoIGdydXBwaWVyZW4sIEFuemFobCBiZXJlY2huZW4gdW5kIHNvcnRpZXJlbg0KYGBge3J9DQpsYW5kdGFnX3BhcnRlaSA8LSBQYXJsYW1lbnRhcmllciAlPiUgDQogIGZpbHRlcihLYXRlZ29yaWUgIT0iQnVuZGVzdGFnIikgJT4lIA0KICBmaWx0ZXIoS2F0ZWdvcmllIT0iRVUtUGFybGFtZW50IikgJT4lIA0KICBmaWx0ZXIoUGFydGVpICE9IkJJVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IlNTVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IkJWQi9GVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IkZXIikNCmBgYA0KDQpgYGB7cn0NCmxhbmR0YWdfcGFydGVpJFBhcnRlaVtsYW5kdGFnX3BhcnRlaSRQYXJ0ZWkgPT0gIkNTVSJdIDwtIkNEVS9DU1UiDQpsYW5kdGFnX3BhcnRlaSRQYXJ0ZWlbbGFuZHRhZ19wYXJ0ZWkkUGFydGVpPT0iQ0RVIl0gPC0gIkNEVS9DU1UiDQpsYW5kdGFnX3BhcnRlaSRQYXJ0ZWlbbGFuZHRhZ19wYXJ0ZWkkUGFydGVpPT0iRkRQL0RWUCJdIDwtICJGRFAiIA0KYGBgDQoNCmBgYHtyfQ0KbGFuZHRhZ19tYW4gPC0gbGFuZHRhZ19wYXJ0ZWkgJT4lIA0KICBncm91cF9ieShQYXJ0ZWkpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQ9PSJtw6RubmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZShnZXNhbXRfbWFuPW4oKSkNCg0KbGFuZHRhZ19nZXNhbXQgPC0gbGFuZHRhZ19wYXJ0ZWkgJT4lIA0KICBncm91cF9ieShQYXJ0ZWkpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQ9PSJ3ZWlibGljaCIpICU+JSANCiAgc3VtbWFyaXNlKGdlc2FtdF9mcmF1PW4oKSkgJT4lIA0KICBsZWZ0X2pvaW4obGFuZHRhZ19tYW4pICU+JSANCiAgIG11dGF0ZShyb3dfc3VtPXJvd1N1bXMoLlsyOjNdKSkgJT4lIA0KICBhcnJhbmdlKGRlc2Mocm93X3N1bSkpDQpgYGANCg0KIyMjIEJhcmNoYXJ0IExhbmR0YWcNCg0KKiBTdGFja2VkLUJhcmNoYXJ0IHp1ciBHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIGluIGRlbiBMYW5kdGFnZW4gcHJvIFBhcnRlaQ0KKiB2aXN1YWxpc2llcnVuZyBkZXIgRGF0ZW4gaW4gbcO2Z2xpY2hzdCBnZXNjaGxlY2h0ZXJuZXVyYWxlbiBGYXJiZW4NCmBgYHtyfQ0KcGxvdF9seShkYXRhPWxhbmR0YWdfZ2VzYW10LCB4PX5yZW9yZGVyKFBhcnRlaSwtcm93X3N1bSksIHk9fmdlc2FtdF9mcmF1LCBuYW1lPSJ3ZWlibGljaCIsIG1hcmtlcj1saXN0KGNvbG9yPXRvUkdCKCIjRkI3RjYyIikpLCANCiAgICAgICAgdHlwZT0iYmFyIiwgaG92ZXJpbmZvPSJ0ZXh0IiwgdGV4dD1+cGFzdGUoIiIscm93X3N1bSksIA0KICAgICAgICBob3ZlcnRlbXBsYXRlPXBhc3RlKCJBbnphaGw6ICV7eTosLjBmfSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+R2VzYW10YW56YWhsOiAle3RleHR9IikpICU+JSANCiAgYWRkX3RyYWNlKHk9fmdlc2FtdF9tYW4sIG5hbWU9Im3DpG5ubGljaCIsIG1hcmtlcj1saXN0KGNvbG9yPXRvUkdCKCIjNzc1Mjg1IikpKSAlPiUgDQogIGxheW91dChiYXJtb2RlPSJzdGFjayIsIHRpdGxlPSJHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIGluIGRlbiBQYXJ0ZWllbiBpbiBkZW4gTGFuZHRhZ2VuIiwgIyB0aXRlbCBwb3NpdGlvbiB1bmQgZ3LDtsOfZSDDpG5kZXJuDQogICAgICAgICB4YXhpcz1saXN0KHRpdGxlPSIiKSwgeWF4aXM9bGlzdCh0aXRsZT0iQW56YWhsIEFiZ2VvcmRuZXRlIikpICU+JQ0KICBsYXlvdXQobGVnZW5kPWxpc3QoeD0xLCB5PTAuNSkpDQpgYGANCg0KIyBNYXAgbWl0IEdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW4gZGVuIExhbmR0YWdlbg0KDQoqIEFsbGUgTGFuZHRhZ2UgaGVyYXVzZmlsdGVybg0KYGBge3J9DQpwYXJsYW1lbnRhcmllcl9sYW5kdGFnIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgZmlsdGVyKEthdGVnb3JpZSAlaW4lIGMoIkFiZ2VvcmRuZXRlbmhhdXMgdm9uIEJlcmxpbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiQmF5ZXJpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiQnJlbWlzY2hlIELDvHJnZXJzY2hhZnQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkhhbWJ1cmdpc2NoZSBCw7xyZ2Vyc2NoYWZ0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJIZXNzaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbmR0YWcgQnJhbmRlbmJ1cmciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbmR0YWcgZGVzIFNhYXJsYW5kZXMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbmR0YWcgTWVja2xlbmJ1cmctVm9ycG9tbWVybiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBOb3JkcmhlaW4tV2VzdGZhbGVuIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJMYW5kdGFnIFJoZWlubGFuZC1QZmFseiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBTYWNoc2VuLUFuaGFsdCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyB2b24gQmFkZW4tV8O8cnR0ZW1iZXJnIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJOaWVkZXJzw6RjaHNpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiU8OkY2hzaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlNjaGxlc3dpZy1Ib2xzdGVpbmlzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJUaMO8cmluZ2VyIExhbmR0YWciKSkNCmBgYA0KDQoqIFZla3RvcmVuIHVuZCBEYXRhZnJhbWUgZXJzdGVsbGVuIG1pdCBkZW4gS29vcmRpbmF0ZW4gYW4gZGVuZW4gZGllIHNww6R0ZXJlbiBQaWUtQ2hhcnRzIGZpeGllcnQgd2VyZGVuIHNvbGxlbi4gKEltbWVyIGdlbmF1IGltIE1pdHRlbHB1bmt0IGRlcyBCdW5kZXNsYW5kZXMpDQoNCmBgYHtyfQ0KS2F0ZWdvcmllIDwtIGMoIkFiZ2VvcmRuZXRlbmhhdXMgdm9uIEJlcmxpbiIsIA0KICAgICAgICAgICAgICAgIkJheWVyaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICJCcmVtaXNjaGUgQsO8cmdlcnNjaGFmdCIsDQogICAgICAgICAgICAgICAiSGFtYnVyZ2lzY2hlIELDvHJnZXJzY2hhZnQiLCANCiAgICAgICAgICAgICAgICJIZXNzaXNjaGVyIExhbmR0YWciLA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgQnJhbmRlbmJ1cmciLCANCiAgICAgICAgICAgICAgICJMYW5kdGFnIGRlcyBTYWFybGFuZGVzIiwNCiAgICAgICAgICAgICAgICJMYW5kdGFnIE1lY2tsZW5idXJnLVZvcnBvbW1lcm4iLA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgTm9yZHJoZWluLVdlc3RmYWxlbiIsDQogICAgICAgICAgICAgICAiTGFuZHRhZyBSaGVpbmxhbmQtUGZhbHoiLA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgU2FjaHNlbi1BbmhhbHQiLCANCiAgICAgICAgICAgICAgICJMYW5kdGFnIHZvbiBCYWRlbi1Xw7xydHRlbWJlcmciLCANCiAgICAgICAgICAgICAgICJOaWVkZXJzw6RjaHNpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgIlPDpGNoc2lzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAiU2NobGVzd2lnLUhvbHN0ZWluaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICJUaMO8cmluZ2VyIExhbmR0YWciKQ0KDQpsYXQgPC0gYyg1Mi41MjAwMDgsDQogICAgICAgICA0OC45MTc0MzEsDQogICAgICAgICA1My4wNzQ5ODIsDQogICAgICAgICA1My41NTM4MTUsDQogICAgICAgICA1MC42NTIwNTIsDQogICAgICAgICA1Mi40MDg0MTgsDQogICAgICAgICA0OS4zOTY0MjMsDQogICAgICAgICA1My42MTI2NTEsDQogICAgICAgICA1MS40MzMyMzcsDQogICAgICAgICA1MC4xMTgzNDYsDQogICAgICAgICA1MS45NTAyNjUsDQogICAgICAgICA0OC42NjE2MDQsDQogICAgICAgICA1Mi42MzY3MDQsDQogICAgICAgICA1MS4xMDQ1NDEsDQogICAgICAgICA1NC4yMTkzNjcsDQogICAgICAgICA1MS4wMTA5ODkpDQoNCmxuZyA8LSBjKDEzLjQwNDk1NCwNCiAgICAgICAgIDExLjQwNzk4MCwNCiAgICAgICAgIDguODA3MDgwLA0KICAgICAgICAgOS45OTE1NzUsDQogICAgICAgICA5LjE2MjQzOCwNCiAgICAgICAgIDEyLjU2MjQ5MiwNCiAgICAgICAgIDcuMDIyOTYxLA0KICAgICAgICAgMTIuNDI5NTk1LA0KICAgICAgICAgNy42NjE1OTQsDQogICAgICAgICA3LjMwODk1MywNCiAgICAgICAgIDExLjY5MjI3NCwNCiAgICAgICAgIDkuMzUwMTM0LA0KICAgICAgICAgOS44NDUwNzcsDQogICAgICAgICAxMy4yMDE3MzgsDQogICAgICAgICA5LjY5NjExNywNCiAgICAgICAgIDEwLjg0NTM0NikNCg0KYnVuZGVzbGFlbmRlcl9rb29yZGluYXRlbiA8LSBkYXRhLmZyYW1lKEthdGVnb3JpZSwgbGF0LCBsbmcpDQpgYGANCg0KKiBEYXRhZnJhbWUgbmFjaCBBbnphaGwgZGVyIG3DpG5ubGljaGVuIHVuZCB3ZWlibGljaGVuIFBvbGl0aWtlcippbm5lbiBwcm8gQnVuZGVzbGFuZCBmaWx0ZXJuLg0KDQpgYGB7cn0NCnBhcmxhbWVudGFyaWVyX21hbiA8LSBwYXJsYW1lbnRhcmllcl9sYW5kdGFnICU+JSANCiAgZ3JvdXBfYnkoS2F0ZWdvcmllKSAlPiUgDQogIGZpbHRlcihHZXNjaGxlY2h0ID09ICJtw6RubmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZShtw6RubmxpY2ggPSBuKCkpDQoNCnBhcmxhbWVudGFyaWVyX2xhbmR0YWdfZ2VzYW10IDwtIHBhcmxhbWVudGFyaWVyX2xhbmR0YWcgJT4lIA0KICBncm91cF9ieShLYXRlZ29yaWUpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQgPT0gIndlaWJsaWNoIikgJT4lIA0KICBzdW1tYXJpc2Uod2VpYmxpY2ggPSBuKCkpICU+JSANCiAgbGVmdF9qb2luKHBhcmxhbWVudGFyaWVyX21hbikNCmBgYA0KDQoqIEtvb3JkaW5hdGVuIGRlciBzcMOkdGVyZW4gUGllLUNoYXJ0cyB6dXIgSGF1cHR0YWJlbGxlIGpvaW5lbg0KDQpgYGB7cn0NCnBhcmxhbWVudGFyaWVyX2tvb3JkaW5hdGVuIDwtIHBhcmxhbWVudGFyaWVyX2xhbmR0YWdfZ2VzYW10ICU+JSANCiAgbGVmdF9qb2luKGJ1bmRlc2xhZW5kZXJfa29vcmRpbmF0ZW4sIGJ5ID0gYygiS2F0ZWdvcmllIiA9ICJLYXRlZ29yaWUiKSkNCmBgYA0KDQojIE1hcCBtaXQgUGllLUNoYXJ0cw0KDQoqIGdlc2NobGVjaHRlcm5ldXRyYWxlIEZhcmJlbiBmw7xyIGRpZSBHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIGVyc3RlbGxlbiwgc293aWUgZGllIEdyZW56ZW4gZGVyIEJ1bmRlc2zDpG5kZXIgaW1wb3J0aWVyZW4gdW5kIG1pdCBOYW1lbiB2ZXJzZWhlbiAocG9wdXApLg0KYGBge3J9DQpjb2xvcnMgPC0gYygiI0ZCN0Y2MiIsICIjNzc1Mjg1IikNCg0KZ3JlbnplbiA8LSByZWFkUkRTKCJEYXRhL2dhZG0zNl9ERVVfMV9zcC5yZHMiKSAlPiUgDQogIHN0X2FzX3NmKCkNCg0KcG9wdXBfYnVuZGVzbGFlbmRlciA8LSBwYXN0ZTAoIjxzdHJvbmc+QnVuZGVzbGFuZDogPC9zdHJvbmc+IiwgZ3JlbnplbiROQU1FXzEpDQpgYGANCg0KKiBQaWUtQ2hhcnRzIG1pdCBIaWxmZSB2b24gYWRkTWluaWNoYXJ0cyB6dXIgS2FydGUgYW5nZWbDvGd0LiANCg0KYGBge3J9DQptYXAgPC0gbGVhZmxldCgpICU+JSANCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Wb3lhZ2VyTGFiZWxzVW5kZXIpICU+JSANCiAgc2V0VmlldyhsbmcgPSAxMC40NTE1MjYsIGxhdCA9IDUxLjE2NTY5MSwgem9vbSA9IDUuNSkgJT4lIA0KICBhZGRQb2x5Z29ucyhkYXRhID0gZ3JlbnplbiwNCiAgICAgICAgICAgICAgZmlsbENvbG9yID0gImdyZXkiLA0KICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuMSwNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMywNCiAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleSIsDQogICAgICAgICAgICAgIHBvcHVwID0gcG9wdXBfYnVuZGVzbGFlbmRlcikgJT4lIA0KICBhZGRNaW5pY2hhcnRzKA0KICAgIHBhcmxhbWVudGFyaWVyX2tvb3JkaW5hdGVuJGxuZywgcGFybGFtZW50YXJpZXJfa29vcmRpbmF0ZW4kbGF0LA0KICAgIHR5cGUgPSAicGllIiwNCiAgICBjaGFydGRhdGEgPSBwYXJsYW1lbnRhcmllcl9rb29yZGluYXRlblssIGMoIndlaWJsaWNoIiwgIm3DpG5ubGljaCIpXSwNCiAgICBjb2xvclBhbGV0dGUgPSBjb2xvcnMsDQogICAgd2lkdGggPSA0NiwNCiAgICBoZWlnaHQgPSA0NiwNCiAgICBvcGFjaXR5ID0gMC44LA0KICAgIGxlZ2VuZFBvc2l0aW9uID0gImJvdHRvbXJpZ2h0Ig0KICApDQptYXANCmBgYA0KDQojIFR3ZWV0cyBkZXIgUG9saXRpa2VyKmlubmVuIHNjcmFwZW4NCg0KTmljaHQgYWxzIGF1c2bDvGhyYmFyZW4gQ29kZSwgZGFtaXQgZGllIERhdGVuIG5pY2h0IG5vY2htYWxzIGdlem9nZW4gd2VyZGVuLi4uDQoNClR3aXR0ZXJfYWNjb3VudHMgPC0gUGFybGFtZW50YXJpZXIgJT4lDQogIGZpbHRlcihLYXRlZ29yaWUhPSJFVS1QYXJsYW1lbnQiKSAlPiUNCiAgZmlsdGVyKFBhcnRlaSE9IkJJVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IlNTVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IkJWQi9GVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IkZXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iZnJha3Rpb25zbG9zIikgJT4lIA0KICBmaWx0ZXIoU01fVHdpdHRlcl91c2VyICE9ICIiKQ0KDQp0b2tlbiA8LSBnZXRfdG9rZW4oKQ0KdG9rZW4NCg0KYWxsZV90d2VldHMgPC0gbGlzdCgpDQp1c2VySWRMaXN0ID0gbGlzdChUd2l0dGVyX2FjY291bnRzJFNNX1R3aXR0ZXJfdXNlcikNCnJsIDwtIHJhdGVfbGltaXQodG9rZW4sICJzdGF0dXNlcy91c2VyX3RpbWVsaW5lIikNCmZvcih1c2VyIGluIHVzZXJJZExpc3RbWzFdXSl7DQogIGFsbGVfdHdlZXRzW1t1c2VyXV0gPC0gZ2V0X3RpbWVsaW5lKHVzZXIsIG4gPSAyLCBjaGVjayA9IEYpDQogIHByaW50KCJyYXRlIGxpbWl0IHJlbWFpbmluZzoiLCBzdHIocmwkcmVtYWluaW5nKSkNCiAgcHJpbnQoImF0IHVzZXI6Iiwgc3RyKHVzZXIpKQ0KICBybCA8LSBybCAlPiUNCiAgICBtdXRhdGUocmVtYWluaW5nID0gcmVtYWluaW5nIC0gMSkNCiAgIyBpZiByYXRlIGxpbWl0IGV4aGF1c3RlZCwgdGhlbiB3YWl0IHRvIHJhdGUgbGltaXQgcmVzZXQNCiAgaWYgKHJsJHJlbWFpbmluZyA9PSA1TCkgew0KICAgIHJsIDwtIHJhdGVfbGltaXQodG9rZW4sICJzdGF0dXNlcy91c2VyX3RpbWVsaW5lIikNCiAgICBwcmludCgicmF0ZSBsaW1pdCBleGNlZWRlZCwgd2FpdGluZyBmb3IgOTAwcyBhdCB1c2VyIiwgc3RyKHVzZXIpKQ0KICAgIFN5cy5zbGVlcChhcy5udW1lcmljKHJsJHJlc2V0LCAic2VjcyIpKQ0KICB9DQp9DQoNCiMjIyBOYWNoIHJlbGV2YW50ZW4gSGFzaHRhZ3MgZmlsdGVybiANCg0KKiAiYWxsZV90d2VldHMucmRzIiBpc3QgZGllIERhdGVpIG1pdCBhbGxlbiBnZXpvZ2VuZW4gVHdlZXRzLg0KKiBuYWNoIHJlbGV2YW50ZW4gVHdlZXRzIGZpbHRlcm4gbWl0IHZvcmhlciBiZXN0aW1tdGVuIEhhc2h0YWdzICgiVHdpdHRlci1IYXNodGFncy54bHN4IiksIFR3ZWV0cyBpbiBLbGVpbnNjaHJlaWJ1bmcgZm9ybWF0aWVyZW4gdW5kIGFscyAiZmluYWxfdHdlZXRzLnJkcyIgZXhwb3J0aWVyZW4uIA0KYGBge3J9DQphbGxlX3R3ZWV0cyA8LSByZWFkX3JkcygiRGF0YS9hbGxlX3R3ZWV0cy5yZHMiKQ0KDQpzdWNoYmVncmlmZmUgPC0gcmVhZF9leGNlbCgiRGF0YS9Ud2l0dGVyLUhhc2h0YWdzLnhsc3giLCBzaGVldCA9IlRhYmVsbGUyIikNCg0Kc3VjaGJlZ3JpZmZlX3ZlY3RvciA8LSBzdWNoYmVncmlmZmUkSGFzaHRhZ3MNCg0KYWxsZV90d2VldHMgPC0gYmluZF9yb3dzKGFsbGVfdHdlZXRzKQ0KDQphbGxlX3R3ZWV0cyA8LSBhbGxlX3R3ZWV0cyAlPiUgDQogIG11dGF0ZSh0ZXh0ID0gdG9sb3dlcih0ZXh0KSkNCg0KZmlsdGVydF90d2VldHMgPC0gYWxsZV90d2VldHMgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdCh0ZXh0LCBwYXN0ZSAoc3VjaGJlZ3JpZmZlX3ZlY3RvciwgY29sbGFwc2UgPSAifCIpKSkNCg0Kd3JpdGVfcmRzKGZpbHRlcnRfdHdlZXRzLCAiZmluYWxfdHdlZXRzLnJkcyIpDQpgYGANCg0KIyBTZW50aW1lbnRhbmFseXNlDQoNCiogbmFjaCBkZW4gImdyb8OfZW4iIFBhcnRlaWVuIGZpbHRlcm4NCiogYWxsZSBQb2xpdGlrZXIqaW5uZW4gZW50ZmVybmVuLCB3ZWxjaGUga2VpbmVuIFR3aXR0ZXJhY2NvdW50IGJlc2l0emVuDQoqIFVzZXJuYW1lcyBpbiBLbGVpbnNjaHJlaWJ1bmcgZm9ybWF0aWVyZW4NCmBgYHtyfQ0KUGFybGFtZW50YXJpZXJfc2VudGkgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iQklXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iU1NXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iQlZCL0ZXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iRlciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJmcmFrdGlvbnNsb3MiKSAlPiUgDQogIGZpbHRlcihTTV9Ud2l0dGVyX3VzZXIgIT0gIiIpICU+JSANCiAgc2VsZWN0KE5hbWUsIFBhcnRlaSwgU01fVHdpdHRlcl91c2VyLCBHZXNjaGxlY2h0KSAlPiUgDQogIG11dGF0ZShTTV9Ud2l0dGVyX3VzZXI9dG9sb3dlcihTTV9Ud2l0dGVyX3VzZXIpKQ0KYGBgDQoNCiogQ0RVICYgQ1NVIHNvd2llIEZEUCAmIERWUCB6dXNhbW1lbmbDvGdlbiANCmBgYHtyfQ0KUGFybGFtZW50YXJpZXJfc2VudGkkUGFydGVpW1BhcmxhbWVudGFyaWVyX3NlbnRpJFBhcnRlaSA9PSAiQ1NVIl0gPC0gIkNEVS9DU1UiDQpQYXJsYW1lbnRhcmllcl9zZW50aSRQYXJ0ZWlbUGFybGFtZW50YXJpZXJfc2VudGkkUGFydGVpID09ICJDRFUiXSA8LSAiQ0RVL0NTVSINClBhcmxhbWVudGFyaWVyX3NlbnRpJFBhcnRlaVtQYXJsYW1lbnRhcmllcl9zZW50aSRQYXJ0ZWkgPT0gIkZEUC9EVlAiXSA8LSAiRkRQIiANCmBgYA0KDQoqIFNlbnRpV1MgaW1wb3J0aWVyZW4sIHVtIHBvc2l0aXZlIHVuZCBuZWdhdGl2ZSBXw7ZydGVyIHp1IGtsYXNzaWZpemllcmVuDQoqIExpc3RlIHp1ciBTZW50aW1lbnRhbmFseXNlIGlzdCB2b24gVW5pdmVyc2l0w6R0IExlaXB6aWc6ICJodHRwczovL3dvcnRzY2hhdHoudW5pLWxlaXB6aWcuZGUvZGUvZG93bmxvYWQiDQpgYGB7cn0NCmxvYWQoIkRhdGEvc2VudGlXUy5SRGF0YSIpDQpzZW50aXdzIDwtIGRpY3Rpb25hcnkobGlzdChwb3NpdGl2ZT1wb3NpdGl2ZSwgbmVnYXRpdmU9bmVnYXRpdmUpKQ0KYGBgDQoNCiogQ29ycHVzIGF1cyBkZW4gVGV4dGVuIGRlciBnZWZpbHRlcnRlbiBUd2VldHMgYmlsZGVuDQpgYGB7cn0NCnR3ZWV0X2NvcnB1cyA8LSBjb3JwdXMoZmlsdGVydF90d2VldHMsIHRleHRfZmllbGQgPSAidGV4dCIpDQpgYGANCg0KKiB0b2tlbmlzaWVyZW4gZGVyIFRleHRlIHVuZCBiaWxkZW4gZWluZXIgREZNDQoqIHNlbnRpd3MgdW5kICJUd2VldC1Ub2tlbnMiIHp1c2FtbWVuZsO8aHJlbiwgc293aWUgbmFjaCBzY3JlZW5fbmFtZSBncnVwcGllcmVuDQoNCmBgYHtyfQ0KdG9rZW4gPC0gdG9rZW5zKHR3ZWV0X2NvcnB1cykNCmRmbSA8LSBkZm0odG9rZW4pDQoNCnNlbnRpIDwtIGRmbV9sb29rdXAoZGZtLCBzZW50aXdzKSAgDQpzZW50aSA8LSBkZm1fZ3JvdXAoc2VudGksIGdyb3VwcyA9IHNjcmVlbl9uYW1lKQ0KYGBgDQoNCiogREZNIHp1bSBEYXRhZnJhbWUga29udmVydGllcmVuDQoqIGRvY19pZCBpbiBLbGVpbnNjaHJlaWJ1bmcgZm9ybWF0aWVyZW4NCiogUGFybGFtZW50YXJpZXJfc2VudGkgam9pbmVuDQoqIEdydXBwaWVyZW4gbmFjaCBQYXJ0ZWkNCiogU2VudGltZW50IGRlciBlaW56ZWxuZW4gVXNlcippbm5lbiBhdWYgUGFydGVpZWJlbmUgenVzYW1tZW5mYXNzZW4gdW5kIFZlcmjDpGx0bmlzIHBvc2l0aXZlL25lZ2F0aXZlIGJpbGRlbg0KYGBge3J9DQpzZW50aV9mcmFtZSA8LSBzZW50aSAlPiUgDQogIGNvbnZlcnQodG89ICJkYXRhLmZyYW1lIikgJT4lIA0KICBhc190aWJibGUoKSAlPiUgDQogIG11dGF0ZShkb2NfaWQ9dG9sb3dlcihkb2NfaWQpKQ0KDQpzZW50aV9maW5hbF9mcmFtZSA8LSBzZW50aV9mcmFtZSAlPiUgDQogIGZ1bGxfam9pbihQYXJsYW1lbnRhcmllcl9zZW50aSwgYnk9YygiZG9jX2lkIj0iU01fVHdpdHRlcl91c2VyIikpICU+JSANCiAgZ3JvdXBfYnkoUGFydGVpKSAlPiUgDQogIHN1bW1hcmlzZShhY3Jvc3MoYyhuZWdhdGl2ZSwgcG9zaXRpdmUpLCB+cm91bmQoc3VtKC4sIG5hLnJtID0gVFJVRSkvc3VtKG5lZ2F0aXZlICsgcG9zaXRpdmUsIG5hLnJtID0gVFJVRSApLCBkaWdpdHMgPSAyKSkpDQpgYGANCg0KIyMjIEJhcmNoYXJ0DQoNCiogUGFydGVpIGFic3RlaWdlbmQgbmFjaCBuZWdhdGl2ZW0gU2VudGltZW50IHNvcnRpZXJlbg0KKiBCZXNjaHJpZnR1bmcgZGVyIFgtIHVuZCBZIFdlcnRlIMOkbmRlcm4NCiogQmFyY2hhcnQgYmlsZGVuIHVuZCBpbiBnZ3Bsb3RseSBrb252ZXJ0aWVyZW4NCmBgYHtyfQ0Kc2VudGlfYmFyIDwtIHNlbnRpX2ZpbmFsX2ZyYW1lICU+JSANCiAgbXV0YXRlKFBhcnRlaSA9IGZjdF9yZW9yZGVyKFBhcnRlaSwgcG9zaXRpdmUsIG1heCkpICU+JSANCiAgcGl2b3RfbG9uZ2VyKGMocG9zaXRpdmUsIG5lZ2F0aXZlKSwgdmFsdWVzX3RvID0gYygiVmVyaMOkbHRuaXMiKSwgbmFtZXNfdG8gPSBjKCLDhHXDn2VydW5nIikpICU+JSANCiAgZ2dwbG90KCkgKyANCiAgZ2VvbV9iYXIoYWVzKFBhcnRlaSwNCiAgICAgICAgICAgICAgIFZlcmjDpGx0bmlzLCAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgZmlsbCA9IMOEdcOfZXJ1bmcpLA0KICAgICAgICAgICBwb3NpdGlvbiA9ICJzdGFjayIsDQogICAgICAgICAgIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNmNDY2NjYiLCAiIzhFQzlCQiIpKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgbGFicygNCiAgICB0aXRsZSA9ICLDhHXDn2VydW5nZW4gZGVyIFBvbGl0aWtlcippbm5lbiBhdWYgVHdpdHRlciB6dW0gVGhlbWEgJ0dlbmRlciciLA0KICAgIHN1YnRpdGxlID0gIkVpbnNjaMOkdHp1bmcgZHVyY2ggU2VudGltZW50YW5hbHlzZSIsDQogICAgeCA9ICJQYXJ0ZWkiLA0KICAgIHkgPSAiVmVyaMOkbHRuaXMiLA0KICAgIGZpbGwgPSAiw4R1w59lcnVuZyINCiAgKQ0KDQpmaW5hbF9zZW50aV9wbG90IDwtIGdncGxvdGx5KHNlbnRpX2JhcikNCmZpbmFsX3NlbnRpX3Bsb3QNCmBgYA0KDQojIFR3aXR0ZXIgTmV0endlcmsgDQoNCiogZmlsdGVydF90d2VldHMgInZlcmtsZWluZXJuIiB1bmQgaW4gdHdlZXRzX25ldHdvcmsgc3BlaWNoZXJuDQoqIHNjcmVlbl9uYW1lIGluIEtsZWluc2NocmVpYnVuZyBmb3JtYXRpZXJlbg0KYGBge3J9DQp0d2VldHNfbmV0d29yayA8LSBmaWx0ZXJ0X3R3ZWV0cyAlPiUgDQogIHNlbGVjdChzY3JlZW5fbmFtZSwNCiAgICAgICAgIHJldHdlZXRfc2NyZWVuX25hbWUsDQogICAgICAgICBjcmVhdGVkX2F0KSAlPiUgDQogIG11dGF0ZShzY3JlZW5fbmFtZSA9IHRvbG93ZXIoc2NyZWVuX25hbWUpKQ0KYGBgDQoNCiogUGFybGFtZW50YXJpZXIgRGF0YWZyYW1lIG1pdCB0d2VldHNfbmV0d29yayBqb2luZW4sIHVtIEtsYXJhbWVuIHVuZCBQYXJ0ZWl6dWdlaMO2cmlna2VpdCBkZXIgUG9saXRpa2VyKmlubm5lbiB6dSBiZWtvbW1lbg0KYGBge3J9DQpwYXJsYW1lbnRhcmllcl9uZXR3b3JrIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgc2VsZWN0KE5hbWUsDQogICAgICAgICBQYXJ0ZWksDQogICAgICAgICBTTV9Ud2l0dGVyX3VzZXIpICU+JSANCiAgZHJvcF9uYShTTV9Ud2l0dGVyX3VzZXIpICU+JSANCiAgbXV0YXRlKFNNX1R3aXR0ZXJfdXNlciA9IHRvbG93ZXIoU01fVHdpdHRlcl91c2VyKSkgJT4lIA0KICByZW5hbWUoInNjcmVlbl9uYW1lIiA9ICJTTV9Ud2l0dGVyX3VzZXIiKQ0KDQpuZXR3b3JrX2RhdGEgPC0gcGFybGFtZW50YXJpZXJfbmV0d29yayAlPiUgDQogIGxlZnRfam9pbih0d2VldHNfbmV0d29yaywgYnkgPSAic2NyZWVuX25hbWUiKQ0KYGBgDQoNCiogSMOkdWZpZ2tlaXQgZGVyIFR3ZWV0cyB6dW0gVGhlbWEgYmVyZWNobmVuIA0KKiBIw6R1Zmlna2VpdCB6dSBuZXR3b3JrX2RhdGEgam9pbmVuDQpgYGB7cn0NCmhhdWVmaWdrZWl0X3R3ZWV0cyA8LSBuZXR3b3JrX2RhdGEgJT4lIA0KICBjb3VudChzY3JlZW5fbmFtZSkNCg0KbmV0d29ya19kYXRhIDwtIG5ldHdvcmtfZGF0YSAlPiUgDQogIGxlZnRfam9pbihoYXVlZmlna2VpdF90d2VldHMsIGJ5ID0gInNjcmVlbl9uYW1lIikNCmBgYA0KDQoqIFZla3RvciBkZXIgc2NyZWVuX25hbWVzIGFsbGVyIFBvbGl0aWtlcippbm5lbiBlcnN0ZWxsZW4NCiogcmV0d2VldF9zY3JlZW5fbmFtZSBhdWYgZGllc2Ugc2NyZWVuX25hbWVzIGZpbHRlcm4sIHVtICJGcmVtZHVzZXIqaW5uZW4iIGF1c3p1c2NobGllw59lbiANCmBgYHtyfQ0Kc2NyZWVuX3N1Y2hlIDwtIHBhcmxhbWVudGFyaWVyX25ldHdvcmskc2NyZWVuX25hbWUNCg0KZmlsdGVyZWRfcmV0d2VldGVycyA8LSBuZXR3b3JrX2RhdGEgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdChyZXR3ZWV0X3NjcmVlbl9uYW1lLCBwYXN0ZSAoc2NyZWVuX3N1Y2hlLCBjb2xsYXBzZSA9ICJ8IikpKQ0KYGBgDQoNCiogTmV0eiBtaXQgcmVsZXZhbnRlbiBXZXJ0ZW4gZGVmaW5pZXJlbiBtaXQ6IA0KKiBFZGdlcyA9IHZvbiBzY3JlZW5fbmFtZSB6dSByZXR3ZWV0X3NjcmVlbl9uYW1lDQoqIE5vZGVzID0gUG9saXRpa2VyKmlubmVuIChzY3JlZW5fbmFtZSB1bmQgcmV0d2VldF9zY3JlZW5fbmFtZSkgDQoqIEpvaW5lIGF1ZnMgTmV0eiBQYXJ0ZWl6dWdlaMO2cmlna2VpdCwgS2xhcm5hbWVuIHVuZCBIw6R1Zmlna2VpdCBkZXIgVHdlZXRzIHp1bSBUaGVtYSAobikNCmBgYHtyfQ0KbmV0eiA8LSBmaWx0ZXJlZF9yZXR3ZWV0ZXJzICU+JSANCiAgZmlsdGVyKCFpcy5uYShyZXR3ZWV0X3NjcmVlbl9uYW1lKSkgJT4lIA0KICBzZWxlY3QoZnJvbSA9IHNjcmVlbl9uYW1lLCB0byA9IHJldHdlZXRfc2NyZWVuX25hbWUpICU+JSANCiAgYXNfdGJsX2dyYXBoDQoNCm5ldHogPC0gbmV0eiAlPiUgDQogIG11dGF0ZSgNCiAgICBkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIiksIA0KICAgIGNvbXBvbmVudCA9IGdyb3VwX2NvbXBvbmVudHMoKQ0KICApICU+JSANCiAgbGVmdF9qb2luKG5ldHdvcmtfZGF0YSAlPiUgDQogICAgICAgICAgICAgIHNlbGVjdChOYW1lLCBzY3JlZW5fbmFtZSwgUGFydGVpLCBuKSAlPiUgZGlzdGluY3Qoc2NyZWVuX25hbWUsIC5rZWVwX2FsbCA9IFQpLA0KICAgICAgICAgICAgYnkgPSBjKCAibmFtZSIgPSJzY3JlZW5fbmFtZSIpKSANCmBgYA0KDQoqIEZhcmJlbiBmw7xyIFBhcnRlaWVuIGRlZmluaWVyZW4NCmBgYHtyfQ0KcGFydGVpX2ZhcmJlbiA8LSBsaXN0KA0KICAiQ0RVL0NTVSIgPSAiYmxhY2siLA0KICAiU1BEIiA9ICJyZWQiLA0KICAiQ1NVIiA9ICJibGFjayIsDQogICJGRFAiID0gIiNlMmIwMDciLA0KICAiR1LDnE5FIiA9ICIjMDdDMjNGIiwNCiAgIkxJTktFIiA9ICIjZGU0YzhhIiwgDQogICJBZkQiID0gImJsdWUiDQopDQpgYGANCg0KIyBOZXR6d2Vyaw0KDQpadXdlaXN1bmcgdm9uIEF0dHJpYnV0ZW4gYW4gTm9kZXM6DQoqIFBhcnRlaXp1Z2Vow7ZyaWdrZWl0IGluIEZhcmJlDQoqIEtsYXJuYW1lIGRlciBQb2xpdGlrZXIqaW5uZW4gYWxzIExhYmVsIA0KKiBBbnphaGwgZGVyIFR3ZWV0cyBpbiBHcsO2w59lDQpgYGB7cn0NCm5ldHpfcGxvdCA8LSBuZXR6ICU+JSANCiAgZmlsdGVyKGNvbXBvbmVudCA8PSA2KSAlPiUgDQogIG11dGF0ZShkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIikpICU+JSANCiAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsNCiAgZ2VvbV9lZGdlX2xpbmsoYWxwaGEgPSAwLjI1LCBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoIjUiLCAibW0iKSkpICsNCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhzaXplID0gbiwgY29sb3IgPSBQYXJ0ZWkpKSArIA0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFydGVpX2ZhcmJlbikgKw0KICB0aGVtZV9ncmFwaChiYWNrZ3JvdW5kID0gIndoaXRlIikgKyAjIHRoZW1lDQogIGdlb21fbm9kZV9sYWJlbChhZXMoZmlsdGVyID0gbiA+PSAxNSwgbGFiZWwgPSBOYW1lKSwgcmVwZWwgPSBULCBzaG93LmxlZ2VuZCA9IEYsIGFscGhhID0gMC41KSArICNwb3NpdGlvbiA9ICJqaXR0ZXIiDQogIGxhYnModGl0bGUgPSAiUmV0d2VldC1OZXR6d2Vya2UgZGV1dHNjaGVyIFBvbGl0aWtlcippbm5lbiIsIHNpemUgPSAiQW56YWhsIFR3ZWV0cyIsIHN1YnRpdGxlID0gInp1bSBUaGVtYSAnR2VuZGVyJyBhYiAyMDE2IikNCmBgYA0KYGBge3J9DQpuZXR6X3Bsb3QgDQpgYGANCg0KTk9ERVMgREVVVExJQ0hFUkUgQUJTVFVGVU5HLCBWTFQuIFRIRU1FIEZVTktUSU9OSUVSVCBOSUNIVCBSSUNIVElHDQoNCg0K